// AutoCoffCalc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Config.h"
#include "Seq.h"
#include <iostream>
#include "PatternList.h"
#include "Defines.h"
#include "Pattern.h"
#include "math.h"
#include <fstream>
#include "AutoCalcFramework.h"
#include "Log.h"
#include "Common.h"
#include "PatternInterpolation.h"

using namespace std;

bool InitSeqs();
bool InitPattern();
bool InitInterpolatePoint();
void InterpolateWith6Tap();
void InterpolateWith4Tap();
void InterpolateWithPatternCoff();

bool DumpToBinary();
void InterpolateWithDirection();



int _tmain(int argc, _TCHAR* argv[])
{


	CConfig::GetConfigFromArgs( argc, argv );
	CConfig * config = CConfig::GetConfig();
	CLog * log = CLog::GetInstance();
	if ( !log->Init( config->log_file ) ) return -1;

	config->DumpConfig();


	if ( config->run_full_pattern )
	{
		if ( !InitPattern() ) return -1;
		CPatternList::GetInstance()->Dump();
	}
	else
	{
		if ( !InitSeqs() ) return -1;

		if ( config->run_pattern_static )
		{
			// Run pattern static
			CPatternList * pattern_list = CPatternList::GetInstance();

			pattern_list->InitPatternListFromSeq();
			pattern_list->DumpForPatterns();
		}
		else if ( config->use_dir_inter )
		{
			InterpolateWithDirection();
			CAutoCalcFramework * frame_work = new CAutoCalcFramework();
			frame_work->CalcPSNR( true );
		}
		else if ( config->use_4tap )
		{
			InterpolateWith4Tap();
			CAutoCalcFramework * frame_work = new CAutoCalcFramework();
			frame_work->CalcPSNR( true );
		}
		else if ( config->use_6tap )
		{
			InterpolateWith6Tap();
			CAutoCalcFramework * frame_work = new CAutoCalcFramework();
			frame_work->CalcPSNR( true );
		}
		else if ( config->use_pattern_coff )
		{
			InterpolateWithPatternCoff();
			CAutoCalcFramework * frame_work = new CAutoCalcFramework();
			frame_work->CalcPSNR( true );
		}
		else
		{
			if ( !InitPattern() ) return -1;

			CPatternList::GetInstance()->Dump();

			if ( !InitInterpolatePoint() ) return -1;

			CAutoCalcFramework * frame_work = new CAutoCalcFramework();
			frame_work->Run();
		}
	}

	// DumpToBinary();
	// system( "pause" );

	log->Close();

	return 0;
}

bool InitSeqs()
{
	CConfig * config = CConfig::GetConfig();

	CSeq * seq = new CSeq();

	bool result;

	result = seq->InitFromFile( config->orig_seq_file, config->rec_seq_file, config->frame_width, config->frame_height, config->encode_count );

	if ( !result )
	{
		CLog::GetInstance()->log_stream << "Error in read seq file " << endl;
		return false;
	}

	config->seq = seq;

	return true;
}

bool InitPattern()
{
	CConfig * config = CConfig::GetConfig();
	CPatternList * pattern_list = CPatternList::GetInstance();
	pattern_list->InitPatternListFromFile( config->pattern_file );

	return true;
}

bool InitInterpolatePoint()
{
	
	CPatternList * pattern_list = CPatternList::GetInstance();

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	unsigned char ref_pixel_array[REF_PIXEL_NUMBER];
	int pattern_count = 0; 
	int unpattern_count = 0;

	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{
		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				GetRefPixelArray( x, y, ref_pixel_array, seq->m_ppRecPixelArray[frame], seq->m_iWidth, seq->m_iHeight );

				bool result = pattern_list->DoMatchRefPixelArray( ref_pixel_array, frame, x, y );
				if ( !result )
				{
					unpattern_count++;
				}
				else
				{
					pattern_count++;
				}
			}
		}
	}

	vector<CPattern*>::iterator iter=pattern_list->m_pvecPattern->begin();

	return true;
}


bool DumpToBinary()
{
	CConfig * config = CConfig::GetConfig();
	
	fstream infile;
	infile.open( "interdump.yuv", ios::binary|ios::out );
	if ( !infile.is_open() )
	{
		return false;
	}

	for ( int i=0; i<config->seq->m_iFrameCount; i++ )
	{
		infile.write( (char*) (config->seq->m_ppIntPixelArray[i]), config->seq->m_iWidth * config->seq->m_iHeight * sizeof( unsigned char ) );
	}

	infile.close();
	return true;

}


void InterpolateWith6Tap()
{
	CPatternList * pattern_list = CPatternList::GetInstance();

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	int pattern_count = 0; 
	int unpattern_count = 0;

	unsigned char ref_pixel[6];
	char ref_coff[6] = { 1, -5, 20, 20, -5, 1 };
	char ref_x_offset[6] = { -5, -3, -1, 1, 3, 5 };
	int sum = 0;

	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{
		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				for ( int i=0; i<6; i++ )
				{
					ref_pixel[i] = seq->m_ppIntPixelArray[frame][ y * seq->m_iWidth + x + ref_x_offset[i] ];
				}
				for ( int i=0; i<6; i++ )
				{
					sum += ref_pixel[i] * ref_coff[i];
				}
				sum = sum >> 5;

				if ( sum < 0 ) sum = 0;
				if ( sum >255 ) sum = 255;
		
				seq->m_ppIntPixelArray[frame][y * seq->m_iWidth + x] = sum;
				
				// cout << "X: " << x << " Y: " << y << endl;
			}
		}
	}

}

void InterpolateWith4Tap()
{
	CPatternList * pattern_list = CPatternList::GetInstance();

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	int pattern_count = 0; 
	int unpattern_count = 0;

	unsigned char ref_pixel[4];
	char ref_coff[4] = { -4, 15, 15, -4 };
	char ref_x_offset[4] = { -3, -1, 1, 3 };
	int sum = 0;

	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{
		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				for ( int i=0; i<4; i++ )
				{
					ref_pixel[i] = seq->m_ppIntPixelArray[frame][ y * seq->m_iWidth + x + ref_x_offset[i] ];
				}
				for ( int i=0; i<4; i++ )
				{
					sum += ref_pixel[i] * ref_coff[i];
				}
				sum = sum / 22;

				if ( sum < 0 ) sum = 0;
				if ( sum >255 ) sum = 255;
		
				seq->m_ppIntPixelArray[frame][y * seq->m_iWidth + x] = sum;
				
				// cout << "X: " << x << " Y: " << y << endl;
			}
		}
	}

}


void InterpolateWithPatternCoff()
{
	CPatternList * pattern_list = CPatternList::GetInstance();

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	int pattern_count = 0; 
	int unpattern_count = 0;

	unsigned char ref_pixel[6];
	char ref_coff[6] = { 1, -5, 20, 20, -5, 1 };
	char ref_x_offset[6] = { -5, -3, -1, 1, 3, 5 };
	int sum = 0;

	unsigned char ** int_frame = new unsigned char*[seq->m_iHeight];
	for( int i=0; i<seq->m_iHeight; i++ )
	{
		int_frame[i] = new unsigned char [seq->m_iWidth];
	}


	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{

		for( int i=0; i<seq->m_iHeight; i++ )
		{
			memcpy( int_frame[i], seq->m_ppIntPixelArray[frame]+i*seq->m_iWidth, seq->m_iWidth*sizeof(unsigned char) );
		}

		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				seq->m_ppIntPixelArray[frame][y * seq->m_iWidth + x] = InterpolatePixelWithPattern( int_frame, 16, 16, x%16, y%16, x/16, y/16 );
				
				// cout << "X: " << x << " Y: " << y << endl;
			}
		}
	}

}

